import sys  
from constant import const

codigo=None

def leerArchivo(nombreArchivo):
    archivo=open(nombreArchivo)
    codigo=open(nombreArchivo).read()
    archivo.close()
    return codigo

def componenteLexico():
    numeroLinea=1
    caracter=const.ESP
    estado=const.INICIAL
    lexema=""
    errores=[]
    lexemas=[]
    while (caracter!=""):
        if(caracter==const.ESP or caracter==const.TAB or caracter==const.RET):
            caracter=sigtCaracter()
            continue
        elif(caracter==const.NLI):
            numeroLinea+=1
            caracter=sigtCaracter()
            continue
        
        if(estado==const.INICIAL):
            lexema=""
            if(caracter==const.ESP or caracter==const.TAB):
                estado=const.INICIAL
            elif(caracter==const.NLI):
                numeroLinea+=1
                estado=const.INICIAL
            if(caracter in const.letras):
                estado=const.IDENTIFICADORES
                continue
            elif(caracter in const.digitos):
                estado=const.ENTEROS
                continue
            elif(caracter in const.aritRelacionales):
                estado=const.ARITMETICOS
                continue
            elif(caracter in const.logicos):
                estado=const.LOGICOS
                continue
            elif(caracter in const.simbolosEspeciales):
                estado=const.SIMBOLOS
                continue
            else:
                estado=const.ERROR
                
        elif(estado==const.IDENTIFICADORES):
            lexema+=caracter
            caracter=sigtCaracter()
            if(caracter in const.digitos or caracter in const.letras):
                estado=const.IDENTIFICADORES
            else:
                print lexema+" IDENTIFICADOR"
                estado=const.INICIAL
                compLex=tipoPalabra(lexema)
                lexemas.append(compLex)
        
        elif(estado==const.ENTEROS):
            lexema+=caracter
            caracter=sigtCaracter()
            if(caracter in const.digitos):
                estado=const.ENTEROS
            elif(caracter=='.'):
                estado=const.FLOTANTES
            elif(caracter in const.letras):
                estado=const.IDNOVALIDO
            else:
                print lexema+" ENTERO"
                estado=const.INICIAL
                lexemas.append(["NUMERO ENTERO    ",lexema,lexema])
                
        elif(estado==const.IDNOVALIDO):
            lexema+=caracter
            caracter=sigtCaracter()
            if(caracter in const.letras or caracter in const.digitos):
                estado=const.IDNOVALIDO
            else:
                errores.append([numeroLinea, lexema])
                estado=const.INICIAL
            
        elif(estado==const.FLOTANTES):
            lexema+=caracter
            caracter=sigtCaracter()
            if(caracter in const.digitos):
                estado=const.FLOTANTES
            else:
                print lexema+" FLOTANTE"
                estado=const.INICIAL
                lexemas.append(["NUMERO FLOTANTE    ",lexema,lexema])
                
        elif(estado==const.ARITMETICOS):
            
            if(caracter=='+'):
                caracter=sigtCaracter()
                if(caracter=='+'):
                    print "++ OPERADOR INCREMENTO POSITIVO"
                    lexemas.append(["OPERADOR ARITMETICO", "++","OPERADOR INCREMENTO POSITIVO"])
                    caracter=sigtCaracter()
                elif(caracter=='='):
                    print "+= OPERADOR INCREMENTO"
                    lexemas.append(["OPERADOR ARITMETICO", "+=","OPERADOR INCREMENTO"])
                    caracter=sigtCaracter()
                else:
                    print "+ OPERADOR SUMA"
                    lexemas.append(["OPERADOR ARITMETICO", "+","OPERADOR SUMA"])
                estado=const.INICIAL
                    
            elif(caracter=='-'):
                caracter=sigtCaracter()
                if(caracter=='-'):
                    print "-- OPERADOR INCREMENTO NEGATIVO"
                    lexemas.append(["OPERADOR ARITMETICO", "--","OPERADOR INCREMENTO NEGATIVO"])
                    caracter=sigtCaracter()
                elif(caracter=='='):
                    print "-= OPERADOR DECREMENTO"
                    lexemas.append(["OPERADOR ARITMETICO", "-=","OPERADOR DECREMENTO"])
                    caracter=sigtCaracter()
                else:
                    print "- OPERADOR MENOS"
                    lexemas.append(["OPERADOR ARITMETICO", "-","OPERADOR RESTA"])
                estado=const.INICIAL
                    
            elif(caracter=='*'):
                caracter=sigtCaracter()
                if(caracter=='='):
                    print "*= OPERADOR MULT IGUAL"
                    lexemas.append(["OPERADOR ARITMETICO", "*=","OPERADOR MULT IGUAL"])
                    caracter=sigtCaracter()
                else:
                    print "* OPERADOR MULTIPLICACION"
                    lexemas.append(["OPERADOR ARITMETICO", "*","OPERADOR MULTIPLICACION"])
                estado=const.INICIAL
            
            elif(caracter=='/'):
                caracter=sigtCaracter()
                if(caracter=='='):
                    print "/= OPERADOR DIV IGUAL"
                    lexemas.append(["OPERADOR ARITMETICO", "/=","OPERADOR DIV IGUAL"])
                    caracter=sigtCaracter()
                else:
                    print "/ OPERADOR DIVISION"
                    lexemas.append(["OPERADOR ARITMETICO", "/","OPERADOR DIVISION"])
                estado=const.INICIAL
            
            elif(caracter=='='):
                caracter=sigtCaracter()
                if(caracter=='='):
                    print "== OPERADOR IGUAL A"
                    lexemas.append(["OPERADOR RELACIONAL", "==","OPERADOR IGUAL A"])
                    caracter=sigtCaracter()
                else:
                    print "= OPERADOR ASIGNACION"
                    lexemas.append(["OPERADOR ASIGNACION", "=","OPERADOR ASIGNACION"])
                estado=const.INICIAL
                    
            elif(caracter=='>'):
                caracter=sigtCaracter()
                if(caracter=='='):
                    print ">= OPERADOR MAYOR O IGUAL QUE"
                    lexemas.append(["OPERADOR RELACIONAL", ">=","OPERADOR MAYOR O IGUAL QUE"])
                    caracter=sigtCaracter()
                else:
                    print "> OPERADOR MAYOR QUE"
                    lexemas.append(["OPERADOR RELACIONAL", ">","OPERADOR MAYOR QUE"])
                estado=const.INICIAL
            
            else:
                caracter=sigtCaracter()
                if(caracter=='='):
                    print "<= OPERADOR MENOR O IGUAL QUE"
                    lexemas.append(["OPERADOR RELACIONAL", "<=","OPERADOR MENOR O IGUAL QUE"])
                    caracter=sigtCaracter()
                else:
                    print "< OPERADOR MENOR QUE"
                    lexemas.append(["OPERADOR RELACIONAL", "<","OPERADOR MENOR QUE"])
                estado=const.INICIAL
                    
        elif(estado==const.LOGICOS):
            
            if(caracter=='&'):
                caracter=sigtCaracter()
                if(caracter=='&'):
                    print "&& OPERADOR AND"
                    lexemas.append(["OPERADOR LOGICO", "&&","OPERADOR AND"])
                    estado=const.INICIAL
                else:
                    estado=const.ERROR
                    
            elif(caracter=='|'):
                caracter=sigtCaracter()
                if(caracter=='|'):
                    print "|| OPERADOR OR"
                    lexemas.append(["OPERADOR LOGICO", "||","OPERADOR OR"])
                    estado=const.INICIAL
                else:
                    estado=const.ERROR
                    
            else:
                caracter=sigtCaracter()
                if(caracter=='='):
                    print "!= OPERADOR DIFERENTE DE"
                    lexemas.append(["OPERADOR RELACIONAL", "!=","OPERADOR DIFERENTE DE"])
                else:
                    print "! OPERADOR NEGACION"
                    lexemas.append(["OPERADOR LOGICO", "!","OPERADOR NEGACION"])
                estado=const.INICIAL
                
        elif(estado==const.SIMBOLOS):
            print caracter +" SIMBOLO ESPECIAL"
            lexemas.append(["SIMBOLO ESPECIAL", caracter, const.dictSimbolos[caracter]])
            estado=const.INICIAL
            caracter=sigtCaracter()
               
        else:
            errores.append([numeroLinea,caracter])
            estado=const.INICIAL
            caracter=sigtCaracter()
    crearTablaSimbolos(lexemas, sys.argv[2])
    crearTablaErrores(errores, sys.argv[3])
    
def crearTablaSimbolos(lexemas, nombreArchivo):
    archivo=open(nombreArchivo, 'w')
    archivo.write("Componente lexico\t\tLexema\t\t\tValor")
    archivo.write('\n')
    for linea in lexemas:
        archivo.write("\n"+linea[0]+"\t\t"+linea[1]+"\t\t\t"+linea[2])
    archivo.close()

def crearTablaErrores(errores, nombreArchivo):
    archivo=open(nombreArchivo, 'w')
    archivo.write("Linea de error\tSimbolo")
    archivo.write('\n')
    for linea in errores:
        archivo.write("\n"+str(linea[0])+'\t\t'+linea[1])
    archivo.close()
        
def tipoPalabra(lexema):
    if(const.estructurasSelectivas.has_key(lexema)):
        return ["ESTRUCTURA SELECTIVA",lexema,const.estructurasSelectivas[lexema]]
    elif(const.estructurasRepetitivas.has_key(lexema)):
        return ["ESTRUCTURA REPETITIVA",lexema,const.estructurasRepetitivas[lexema]]
    elif(const.tiposDatos.has_key(lexema)):
        return ["TIPO DE DATO      ",lexema,const.tiposDatos[lexema]]
    elif(const.modificadores.has_key(lexema)):
        return ["MODIFICADORES", lexema, const.modificadores[lexema]]
    elif(const.otros.has_key(lexema)):
        return ["OTROS            ",lexema,const.otros[lexema]]
    else:
        return ["IDENTIFICADOR   ",lexema, lexema]
        
def sigtCaracter():
    if not hasattr(sigtCaracter, "index"):
        sigtCaracter.index = 0 
    else:
        sigtCaracter.index += 1
    if(sigtCaracter.index<len(codigo)):
        return codigo[sigtCaracter.index]
    else:
        return ""


def main():
    if len(sys.argv)!=4:
        print 'La ejecucion debe hacerse de la forma python codigo.py "archivoCodigoC.c" "tablaSimbolos.txt" "archivoErrores.txt'
        sys.exit(0)
    global codigo
    codigo=leerArchivo(sys.argv[1])
    componenteLexico()

main()